//#include "Path.h"
#include "graph.h"

#include <iostream>
#include <fstream>
#include <string>
#include <string.h>

using namespace std;

void auxArchivoAGrafo(const char* file_path, Graph * grafo);

Graph::Graph() {
    tamanioG = 0;
    diametro = 0;
    Costos = NULL;
    Aristas = NULL;
    Terminales = NULL;
}

Graph::Graph(int cantNodos) {

    tamanioG = cantNodos;
    diametro = 0;
    // inicializo las matrices
    Aristas = new int*[cantNodos];
    Costos = new float*[cantNodos];
    Terminales = new int[cantNodos];

    for (int i = 0; i < cantNodos; i++) {
        Costos[i] = new float[cantNodos];
        Aristas[i] = new int[cantNodos];
        for (int j = 0; j < cantNodos; j++) {
            Costos[i][j] = 0;
            Aristas[i][j] = 0;
        }
    }
}

// Esta funcion es para la entrada ppal

Graph::Graph(const char* file_path) {
    Graph(); // construyo el grafo inicial--
    auxArchivoAGrafo(file_path, this);
}

Graph::Graph(Graph* grafoCopia) {
    // realiza una copia limpia..
    tamanioG = grafoCopia->getTamanio();
    diametro = grafoCopia->diametro;

    Terminales = new int[tamanioG];
    //memcpy(Terminales,grafoCopia->getTerminales(), tamanioG * sizeof int);

    // for (int j = 0; j < tamanioG; j++) 
    Costos = new float*[tamanioG];
    Aristas = new int*[tamanioG];

    for (int i = 0; i < tamanioG; i++) {
        Terminales[i] = grafoCopia->getTerminales()[i];

        Costos[i] = new float[tamanioG];
        Aristas[i] = new int[tamanioG];
        //Grafo ...
        for (int j = 0; j < tamanioG; j++) {
            Costos[i][j] = grafoCopia->Costos[i][j];
            Aristas[i][j] = grafoCopia->Aristas[i][j];
        }
    }

}

Graph::~Graph() {
    for (int i = 0; i<this->tamanioG; i++) {
        delete this->Aristas[i];
        delete this->Costos[i];
    }
    delete Aristas;
    delete Costos;
    delete Terminales;


}

void Graph::agregarArista(int nodo1, int nodo2, float costo) {
    //agrego la arista
    this->Aristas[nodo1][nodo2] = 1;
    this->Aristas[nodo2][nodo1] = 1;

    //agrego su costo
    this->Costos[nodo1][nodo2] = costo;
    this->Costos[nodo2][nodo1] = costo;
}

void Graph::quitarArista(int nodo1, int nodo2) {
    //agrego la arista
    this->Aristas[nodo1][nodo2] = 0;
    this->Aristas[nodo2][nodo1] = 0;

    //agrego su costo
    this->Costos[nodo1][nodo2] = 0;
    this->Costos[nodo2][nodo1] = 0;
}

bool Graph::existeArista(int u, int v) {
    return this->Aristas[u][v] || this->Aristas[v][u];
}

bool Graph::esNodoTerminal(int nodo) {
    return this->getTerminales()[nodo];
}

void Graph::setCostos(float** Costos) {
    this->Costos = Costos;
}

float** Graph::getCostos() const {
    return Costos;
}

void Graph::setAristas(int** Aristas) {
    this->Aristas = Aristas;
}

int** Graph::getAristas() const {
    return Aristas;
}

int Graph::getTamanio() {
    return this->tamanioG;
}

void opciones_nodo_gv(bool esTerminal, char* &opciones) {
    if (esTerminal) {
        strcpy(opciones, "shape = doublecircle");
    } else {
        strcpy(opciones, "shape = circle");
    }
}

void Graph::graph_viz() {
    char* opciones = new char[50];
    cout << "graph g{" << endl;
    for (int i = 0; i<this->tamanioG; i++) {
        opciones_nodo_gv(this->Terminales[i], opciones);
        cout << i << " [" << opciones << "];" << endl;
    }
    for (int i = 0; i<this->tamanioG; i++) {
        for (int j = 0; j < i; j++) {
            if (this->Aristas[i][j]) {
                cout << "\t" << i << "--" << j << " [ label=" << this->Costos[i][j] << "];" << endl;
            }
        }
    }
    cout << "}" << endl;
}

void Graph::setTerminales(int* Terminales) {
    this->Terminales = Terminales;
}

int* Graph::getTerminales() const {
    return Terminales;
}


/// Funciones Auxiliares para el grafo...

void auxArchivoAGrafo(const char* file_path, Graph * grafo) {
    string line;
    ifstream file(file_path);
    //funcion pendiente a como lo realizan.. dependiendo de la entrada de ellos.

}